home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / sipp / libsipp / bezier.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-03  |  17.5 KB  |  677 lines

  1. /**
  2.  ** sipp - SImple Polygon Processor
  3.  **
  4.  **  A general 3d graphic package
  5.  **
  6.  **  Copyright Equivalent Software HB  1992
  7.  **
  8.  ** This program is free software; you can redistribute it and/or modify
  9.  ** it under the terms of the GNU General Public License as published by
  10.  ** the Free Software Foundation; either version 1, or any later version.
  11.  ** This program is distributed in the hope that it will be useful,
  12.  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  ** GNU General Public License for more details.
  15.  ** You can receive a copy of the GNU General Public License from the
  16.  ** Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  **/
  18.  
  19. /**
  20.  ** bezier.c - Reading bezier descriptions and creating objects.
  21.  **/
  22.  
  23. #include <math.h>
  24. #include <stdio.h>
  25.  
  26. #include <sipp.h>
  27. #include <smalloc.h>
  28. #include <primitives.h>
  29. #include <bezier.h>
  30.  
  31.  
  32. Tokenval     tokenval;
  33. extern FILE *yyin;
  34.  
  35.  
  36. /*================================================================*/
  37. /*                                                                */
  38. /*      Functions for reading bezier descriptions from file       */
  39. /*                                                                */
  40. /*================================================================*/
  41.  
  42.  
  43. /*
  44.  * Read a vertex list, where each vertex is an xyz triple, and 
  45.  * install it in the bezier structure.
  46.  */
  47. static void
  48. vertex_read(obj)
  49.     Bez_Object *obj;
  50. {
  51.     int token;
  52.     int i, j;
  53.  
  54.     token = yylex();
  55.     if (token != NVERTICES) {
  56.         fprintf(stderr, "Corrupt vertex description.\n");
  57.         goto errout;
  58.     }
  59.     
  60.     token = yylex();
  61.     if (token != INTEGER) {
  62.         fprintf(stderr, "Corrupt vertex description.\n");
  63.         goto errout;
  64.     }
  65.     obj->nvertex = tokenval.intval;
  66.     obj->vertex = (Vector *)smalloc(obj->nvertex * sizeof(Vector));
  67.  
  68.     token = yylex();
  69.     if (token != VERTEX_LIST) {
  70.         fprintf(stderr, "Corrupt vertex description.\n");
  71.         goto errout;
  72.     }
  73.  
  74.     for (i = 0; i < obj->nvertex; i++) {
  75.         for (j = 0; j < 3; j++) {
  76.             token = yylex();
  77.             if (token != FLOAT && token != INTEGER) {
  78.                 fprintf(stderr, "Corrupt vertex description.\n");
  79.                 goto errout;
  80.             }
  81.             switch (j) {
  82.               case 0:
  83.                 if (token == FLOAT) {
  84.                     obj->vertex[i].x = tokenval.floatval;
  85.                 } else {
  86.                     obj->vertex[i].x = (double)tokenval.intval;
  87.                 }
  88.  
  89.               case 1:
  90.                 if (token == FLOAT) {
  91.                     obj->vertex[i].y = tokenval.floatval;
  92.                 } else {
  93.                     obj->vertex[i].y = (double)tokenval.intval;
  94.                 }
  95.  
  96.               case 2:
  97.                 if (token == FLOAT) {
  98.                     obj->vertex[i].z = tokenval.floatval;
  99.                 } else {
  100.                     obj->vertex[i].z = (double)tokenval.intval;
  101.                 }
  102.             }
  103.         }
  104.     }
  105.  
  106.     return;
  107.  
  108.   errout:
  109.     if (obj->vertex != NULL) {
  110.         sfree(obj->vertex);
  111.         obj->vertex = NULL;
  112.     }
  113. }
  114.  
  115.     
  116.  
  117. /*
  118.  * Read a list of bezier curves, where each curve consists of 
  119.  * four control points (index into the vertex list), and install 
  120.  * it in the bezier structure.
  121.  */
  122. static void
  123. curve_read(obj)
  124.     Bez_Object *obj;
  125. {
  126.     int         token;
  127.     int         i, j;
  128.  
  129.     token = yylex();
  130.     if (token != NCURVES) {
  131.         fprintf(stderr, "Corrupt curve description.\n");
  132.         goto errout;
  133.     }
  134.     
  135.     token = yylex();
  136.     if (token != INTEGER) {
  137.         fprintf(stderr, "Corrupt curve description.\n");
  138.         goto errout;
  139.     }
  140.     obj->n.ncurves = tokenval.intval;
  141.     obj->cp.ccp = (Bez_Curve *)smalloc(obj->n.ncurves * sizeof(Bez_Curve));
  142.  
  143.     token = yylex();
  144.     if (token != CURVE_LIST) {
  145.         fprintf(stderr, "Corrupt curve description.\n");
  146.         goto errout;
  147.     }
  148.  
  149.     for (i = 0; i < obj->n.ncurves; i++) {
  150.         for (j = 0; j < 4; j++) {
  151.             token = yylex();
  152.             if (token != INTEGER) {
  153.                 fprintf(stderr, "Corrupt curve description.\n");
  154.                 goto errout;
  155.             }
  156.             obj->cp.ccp[i].cp[3 - j] = tokenval.intval - 1;
  157.         }
  158.     }
  159.  
  160.     return;
  161.  
  162.   errout:
  163.     if (obj->cp.ccp != NULL) {
  164.         sfree(obj->cp.ccp);
  165.         obj->cp.ccp = NULL;
  166.     }
  167. }
  168.  
  169.  
  170.     
  171. /*
  172.  * Read a list of bezier patches, where each patch consists of 
  173.  * sixteen control points (index into the vertex list), and install 
  174.  * it in the bezier structure.
  175.  */
  176. static void
  177. patch_read(obj)
  178.     Bez_Object *obj;
  179. {
  180.     int         token;
  181.     int         i, j, k;
  182.  
  183.     token = yylex();
  184.     if (token != NPATCHES) {
  185.         fprintf(stderr, "Corrupt patch description.\n");
  186.         goto errout;
  187.     }
  188.     
  189.     token = yylex();
  190.     if (token != INTEGER) {
  191.         fprintf(stderr, "Corrupt patch description.\n");
  192.         goto errout;
  193.     }
  194.     obj->n.npatches = tokenval.intval;
  195.     obj->cp.pcp = (Bez_Patch *)smalloc(obj->n.npatches * sizeof(Bez_Patch));
  196.  
  197.     token = yylex();
  198.     if (token != PATCH_LIST) {
  199.         fprintf(stderr, "Corrupt patch description.\n");
  200.         goto errout;
  201.     }
  202.  
  203.     for (i = 0; i < obj->n.npatches; i++) {
  204.         for (j = 0; j < 4; j++) {
  205.             for (k = 0; k < 4; k++) {
  206.                 token = yylex();
  207.                 if (token != INTEGER) {
  208.                     fprintf(stderr, "Corrupt patch description.\n");
  209.                     goto errout;
  210.                 }
  211.                 obj->cp.pcp[i].cp[j][k] = tokenval.intval - 1;
  212.             }
  213.         }
  214.     }
  215.  
  216.     return;
  217.  
  218.   errout:
  219.     if (obj->cp.pcp != NULL) {
  220.         sfree(obj->cp.pcp);
  221.         obj->cp.pcp = NULL;
  222.     }
  223. }
  224.  
  225.  
  226.     
  227. /*
  228.  * Read a bezier object from a file, i.e. determine if it is a
  229.  * curve or patch description,  read vertex and curve or patch 
  230.  * description. Build a bezier object from the data.
  231.  */
  232. static Bez_Object *
  233. bezier_read(file)
  234.     FILE *file;
  235. {
  236.     int token;
  237.     Bez_Object *obj;
  238.  
  239.  
  240.     yyin = file;
  241.  
  242.     obj = (Bez_Object *)scalloc(1, sizeof(Bez_Object));
  243.     if ((token = yylex()) == PATCHES) {
  244.         obj->type = PATCHES;
  245.         vertex_read(obj);
  246.         if (obj->vertex == NULL) {
  247.             goto errout;
  248.         }
  249.         patch_read(obj);
  250.         if (obj->cp.pcp == NULL) {
  251.             goto errout;
  252.         }
  253.     } else if (token == CURVES) {
  254.         obj->type = CURVES;
  255.         vertex_read(obj);
  256.         if (obj->vertex == NULL) {
  257.             goto errout;
  258.         }
  259.         curve_read(obj);
  260.         if (obj->cp.ccp == NULL) {
  261.             goto errout;
  262.         }
  263.     } else {
  264.         fprintf(stderr, "Corrupt bezier description file: %s\n", file);
  265.         return NULL;
  266.     }
  267.  
  268.     return obj;
  269.  
  270.   errout:
  271.     if (obj != NULL) {
  272.         if (obj->vertex != NULL) {
  273.             sfree(obj->vertex);
  274.         }
  275.         if (obj->cp.pcp != NULL) {
  276.             sfree(obj->cp.pcp);
  277.         }
  278.         sfree(obj);
  279.     }
  280.     return NULL;
  281. }
  282.  
  283.  
  284. /*================================================================*/
  285. /*                                                                */
  286. /*           Functions for evaluating bezier functions            */
  287. /*                                                                */
  288. /*================================================================*/
  289.  
  290. static double
  291. C(i)
  292.     int i;
  293. {
  294.     int j, a;
  295.  
  296.     a = 1;
  297.     for (j = i + 1; j < 4; j++) {
  298.         a = a * j;
  299.     }
  300.     for (j = 1 ; j < 4 - i; j++) {
  301.         a = a / j;
  302.     }
  303.  
  304.     return (double)a;
  305. }
  306.  
  307.  
  308. static double 
  309. bblend(i, u)
  310.     int    i;
  311.     double u;
  312. {
  313.     int j;
  314.     double v;
  315.  
  316.     v = C(i);
  317.     for (j = 1; j <= i; j++) {
  318.         v *= u;
  319.     }
  320.     for (j = 1; j < 4 - i; j++) {
  321.         v *= 1.0 - u;
  322.     }
  323.  
  324.     if (fabs(v) < 1.0E-15) {
  325.         return 0.0;
  326.     } else {
  327.         return v;
  328.     }
  329. }
  330.  
  331.  
  332. /*
  333.  * Determine x, y and z coordinates of a point on the bezier
  334.  * curve described by CURVE and VERTEX. U is a parameter between
  335.  * 0 and 1 that determines how far "into" the curve we are.
  336.  */
  337. static void
  338. bez_curve_eval(vertex, curve, u, x, y, z)
  339.     Vector     *vertex;
  340.     Bez_Curve  *curve;
  341.     double      u;
  342.     double     *x, *y, *z;
  343. {
  344.     int    i;
  345.     double b;
  346.  
  347.     *x = 0;
  348.     *y = 0;
  349.     *z = 0;
  350.     
  351.     for (i = 0; i < 4; i++) {
  352.         b = bblend(i, u);
  353.         *x += vertex[curve->cp[i]].x * b;
  354.         *y += vertex[curve->cp[i]].y * b;
  355.         *z += vertex[curve->cp[i]].z * b;
  356.     }
  357. }
  358.  
  359.  
  360. /*
  361.  * Determine x, y and z coordinates of a point on the bezier
  362.  * patch described by PATCH and VERTEX. U and V are parameters
  363.  * between 0 and 1 that determines where on the patch we are.
  364.  */
  365. static void
  366. bez_patch_eval(vertex, patch, v, u, x, y, z)
  367.     Vector     *vertex;
  368.     Bez_Patch  *patch;
  369.     double      u, v;
  370.     double     *x, *y, *z;
  371. {
  372.     int i, j;
  373.     double b;
  374.  
  375.     *x = 0;
  376.     *y = 0;
  377.     *z = 0;
  378.  
  379.     for (i = 0; i < 4; i++) {
  380.         for (j = 0; j < 4; j++) {
  381.             b   = bblend(i, v);
  382.             b  *= bblend(j, u);
  383.             *x += vertex[patch->cp[i][j]].x * b;
  384.             *y += vertex[patch->cp[i][j]].y * b;
  385.             *z += vertex[patch->cp[i][j]].z * b;
  386.         }
  387.     }
  388. }
  389.  
  390.  
  391.  
  392. /*================================================================*/
  393. /*                                                                */
  394. /*             Functions for creating bezier objects              */
  395. /*             (these functions are SIPP specific)                */
  396. /*                                                                */
  397. /*================================================================*/
  398.  
  399.  
  400. /*
  401.  * Approximate the bezier patches described in OBJ with polygons
  402.  * and create a SIPP surface out of them. The patches will be 
  403.  * tesselated into RESxRES polygons (rectangles).
  404.  */
  405. Surface *
  406. bezier_patches(obj, res, surface, shader, texture)
  407.     Bez_Object *obj;
  408.     int         res;
  409.     void       *surface;
  410.     Shader     *shader;
  411.     int         texture;
  412. {
  413.     double  x, y, z;
  414.     double  u, v;
  415.     double  step;
  416.     int     i, j, k;
  417.  
  418.     step = 1.0 / (double)res;
  419.     
  420.     for (i = 0; i < obj->n.npatches; i++) {
  421.         for (v = 0.0, j = 0; j < res; j++, v = j * step) {
  422.             for (u = 0.0, k = 0; k < res; k++, u = k * step) {
  423.                 switch (texture) {
  424.                   case NATURAL:
  425.                   case CYLINDRICAL:
  426.                   case SPHERICAL:
  427.                     bez_patch_eval(obj->vertex, &obj->cp.pcp[i], v, u, 
  428.                                    &x, &y, &z);
  429.                     vertex_tx_push(x, y, z, u, v, 0.0);
  430.                     bez_patch_eval(obj->vertex, &obj->cp.pcp[i], v, u + step,
  431.                                    &x, &y, &z); 
  432.                     vertex_tx_push(x, y, z, u + step, v, 0.0);
  433.                     bez_patch_eval(obj->vertex, &obj->cp.pcp[i], 
  434.                                    v + step, u + step, &x, &y, &z);
  435.                     vertex_tx_push(x, y, z, u + step, v + step, 0.0);
  436.                     bez_patch_eval(obj->vertex, &obj->cp.pcp[i], v + step, u, 
  437.                                    &x, &y, &z);
  438.                     vertex_tx_push(x, y, z, u, v + step, 0.0);
  439.                     break;
  440.                     
  441.                   case WORLD:
  442.                   default:
  443.                     bez_patch_eval(obj->vertex, &obj->cp.pcp[i], v, u, 
  444.                                    &x, &y, &z);
  445.                     vertex_tx_push(x, y, z, x, y, z);
  446.                     bez_patch_eval(obj->vertex, &obj->cp.pcp[i], v, u + step,
  447.                                    &x, &y, &z); 
  448.                     vertex_tx_push(x, y, z, x, y, z);
  449.                     bez_patch_eval(obj->vertex, &obj->cp.pcp[i], 
  450.                                    v + step, u + step, &x, &y, &z);
  451.                     vertex_tx_push(x, y, z, x, y, z);
  452.                     bez_patch_eval(obj->vertex, &obj->cp.pcp[i], v + step, u, 
  453.                                    &x, &y, &z);
  454.                     vertex_tx_push(x, y, z, x, y, z);
  455.                     break;
  456.                 }
  457.                 polygon_push();
  458.             }
  459.         }
  460.     }
  461.     return surface_create(surface, shader);
  462. }
  463.  
  464.  
  465.  
  466. /*
  467.  * Take the bezier curves described in OBJ and create a
  468.  * surface by rotating them about th y-axis. The object
  469.  * will be tesselated as RESx(RES*4) polygons per curve.
  470.  * (The reason for using 4 times the resolution is rather
  471.  * "handwavy". I think 90 degrees is about as much as a
  472.  * patch should cover of a rotational body.)
  473.  */
  474. static Surface *
  475. bezier_rot_curves(obj, res, surface, shader, texture)
  476.     Bez_Object *obj;
  477.     int         res;
  478.     void       *surface;
  479.     Shader     *shader;
  480.     int         texture;
  481. {
  482.     double  x[4], y[4], z[4];
  483.     double  xtmp;
  484.     double  u;
  485.     double  v;
  486.     double  step;
  487.     double  vstep;
  488.     double  ca, sa;
  489.     int     i, j, k;
  490.  
  491.     step = 1.0 / (double)res;
  492.     vstep = step / 4.0;
  493.     ca = cos(2.0 * M_PI / (4.0 * (double)res));
  494.     sa = sin(2.0 * M_PI / (4.0 * (double)res));
  495.  
  496.     for (i = 0; i < obj->n.ncurves; i++) {
  497.         for (u = 0.0, j = 0; j < res; j++, u += step) {
  498.             bez_curve_eval(obj->vertex, &obj->cp.ccp[i], u, 
  499.                            &x[0], &y[0], &z[0]);
  500.             bez_curve_eval(obj->vertex, &obj->cp.ccp[i], u + step, 
  501.                            &x[1], &y[1], &z[1]);
  502.             z[3] = z[0];
  503.             z[2] = z[1];
  504.             for (k = 0; k < 4 * res; k++) {
  505.                 x[3] = ca * x[0] - sa * y[0];
  506.                 y[3] = ca * y[0] + sa * x[0];
  507.                 x[2] = ca * x[1] - sa * y[1];
  508.                 y[2] = ca * y[1] + sa * x[1];
  509.                 switch (texture) {
  510.                   case NATURAL:
  511.                   case CYLINDRICAL:
  512.                   case SPHERICAL:
  513.                     v = k * vstep;
  514.                     vertex_tx_push(x[0], y[0], z[0], v, u, 0.0);
  515.                     vertex_tx_push(x[3], y[3], z[3], 
  516.                                    v + vstep, u, 0.0);
  517.                     vertex_tx_push(x[2], y[2], z[2], 
  518.                                    v + vstep, u + step, 0.0);
  519.                     vertex_tx_push(x[1], y[1], z[1], v, u + step, 0.0);
  520.                     break;
  521.                     
  522.                   case WORLD:
  523.                   default:
  524.                     vertex_tx_push(x[0], y[0], z[0], x[0], y[0], z[0]);
  525.                     vertex_tx_push(x[3], y[3], z[3], x[3], y[3], z[3]);
  526.                     vertex_tx_push(x[2], y[2], z[2], x[2], y[2], z[2]);
  527.                     vertex_tx_push(x[1], y[1], z[1], x[1], y[1], z[1]);
  528.                     break;
  529.                 }
  530.                 polygon_push();
  531.                 x[0] = x[3];
  532.                 y[0] = y[3];
  533.                 x[1] = x[2];
  534.                 y[1] = y[2];
  535.             }
  536.         }
  537.     }
  538.     
  539.     return surface_create(surface, shader);
  540. }
  541.  
  542.  
  543.  
  544. /*
  545.  * Read a bezier description from FILE and build
  546.  * a bezier surface. Tesselate this object into
  547.  * polygons and return a pointer to a SIPP object.
  548.  */
  549. Object *
  550. sipp_bezier_file(file, res, surface, shader, texture)
  551.     FILE    *file;
  552.     int      res;
  553.     void    *surface;
  554.     Shader  *shader;
  555.     int      texture;
  556. {
  557.     Object     *obj;
  558.     Bez_Object *bez_obj;
  559.  
  560.     bez_obj = bezier_read(file);
  561.     if (bez_obj == NULL) {
  562.         return NULL;
  563.     }
  564.  
  565.     obj = object_create();
  566.     if (bez_obj->type == PATCHES) {
  567.         object_add_surface(obj, bezier_patches(bez_obj, res, surface, shader,
  568.                                                texture)); 
  569.         sfree(bez_obj->vertex);
  570.         sfree(bez_obj->cp.pcp);
  571.         sfree(bez_obj);
  572.     } else {
  573.         object_add_surface(obj, bezier_rot_curves(bez_obj, res, surface,
  574.                                                   shader, texture)); 
  575.         sfree(bez_obj->vertex);
  576.         sfree(bez_obj->cp.ccp);
  577.         sfree(bez_obj);
  578.     }
  579.  
  580.     return obj;
  581. }
  582.  
  583.  
  584.  
  585. /*
  586.  * Define an object directly from lists of vertices and control points for
  587.  * one or more bezier patches.
  588.  */
  589. Object *
  590. sipp_bezier_patches(nvert, vertex, npatch, cp_index, res, surface, shader,
  591.                     texture )
  592.     int     nvert;
  593.     Vector *vertex;
  594.     int     npatch;
  595.     int    *cp_index;
  596.     int     res;
  597.     void   *surface;
  598.     Shader *shader;
  599.     int     texture;
  600. {
  601.     Object     *obj;
  602.     Bez_Object  bez_obj;
  603.     int         index;
  604.     int         i, j, k;
  605.  
  606.     bez_obj.type = PATCHES;
  607.  
  608.     bez_obj.nvertex = nvert;
  609.     bez_obj.vertex = vertex;
  610.  
  611.     bez_obj.n.npatches = npatch;
  612.     bez_obj.cp.pcp = (Bez_Patch *)scalloc(npatch, sizeof(Bez_Patch));
  613.  
  614.     for (i = 0, index = 0; i < npatch; i++) {
  615.         for (j = 0; j < 4; j++) {
  616.             for (k = 0; k < 4; k++, index++) {
  617.                 bez_obj.cp.pcp[i].cp[j][k] = cp_index[index];
  618.             }
  619.         }
  620.     }
  621.  
  622.     obj = object_create();
  623.     object_add_surface(obj, bezier_patches(&bez_obj, res, surface, shader,
  624.                                            texture));
  625.  
  626.     sfree(bez_obj.cp.pcp);
  627.  
  628.     return obj;
  629. }
  630.  
  631.  
  632.  
  633. /*
  634.  * Define an object directly from lists of vertices and control points for one
  635.  * ore more bezier curves. The curves will be rotated about the world y-axis to
  636.  * create rotational bodies.
  637.  */
  638. Object *
  639. sipp_bezier_rotcurve(nvert, vertex, ncurve, cp_index, res, surface, shader,
  640.                      texture) 
  641.     int     nvert;
  642.     Vector *vertex;
  643.     int     ncurve;
  644.     int    *cp_index;
  645.     int     res;
  646.     void   *surface;
  647.     Shader *shader;
  648.     int     texture;
  649. {
  650.     Object     *obj;
  651.     Bez_Object  bez_obj;
  652.     int         index;
  653.     int         i, j;
  654.  
  655.     bez_obj.type = CURVES;
  656.  
  657.     bez_obj.nvertex = nvert;
  658.     bez_obj.vertex = vertex;
  659.  
  660.     bez_obj.n.npatches = ncurve;
  661.     bez_obj.cp.ccp = (Bez_Curve *)scalloc(ncurve, sizeof(Bez_Curve));
  662.  
  663.     for (i = 0, index = 0; i < ncurve; i++) {
  664.         for (j = 0; j < 4; j++, index++) {
  665.             bez_obj.cp.ccp[i].cp[j] = cp_index[index];
  666.         }
  667.     }
  668.  
  669.     obj = object_create();
  670.     object_add_surface(obj, bezier_rot_curves(&bez_obj, res, surface, shader,
  671.                                               texture));
  672.  
  673.     sfree(bez_obj.cp.ccp);
  674.  
  675.     return obj;
  676. }
  677.